package com.google.code.gronono.jarseeker.model;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.regex.Pattern;

public class JarSeeker {
	public static final String JAR_EXT = ".jar";
	public static final String CLASS_EXT = ".class";
	public static final char FILE_SEP = '/';
	public static final char PACKAGE_SEP = '.';
	
	public List<ClassFile> findJar(String dirName, String classPattern) throws IOException {
		String patternStr = classPattern.replace(".", "\\.");
		patternStr = patternStr.replace("*", ".*");
		patternStr = patternStr.replace("?", ".");
		
		Pattern pattern = Pattern.compile(patternStr, Pattern.CASE_INSENSITIVE);
		
		return findJar(dirName, pattern);
	}
	
	public List<ClassFile> findJar(String dirName, Pattern classPattern) throws IOException {
		List<ClassFile> jars = new ArrayList<ClassFile>();
		
		File dir = new File(dirName);
		checkDir(dir);
		
		for (File f : dir.listFiles()) {
			if (f.isDirectory()) {
				jars.addAll(findJar(f.getAbsolutePath(), classPattern));
			} else if (f.getName().endsWith(JAR_EXT)){
				jars.addAll(findInJar(f.getAbsolutePath(), classPattern));
			}
		}
		return jars;
	}
	
	private void checkDir(File dir) throws IOException {
		if (!dir.exists()) {
			throw new FileNotFoundException("Le dossier " + dir.getAbsolutePath() + " n'existe pas.");
		}
		if (!dir.isDirectory()) {
			throw new IOException(dir.getAbsolutePath() + " doit être un dossier.");
		}
		if (!dir.canRead()) {
			throw new IOException("Le dossier " + dir.getAbsolutePath() + " n'est pas accessible en lecture.");
		}
	}
	
	private List<ClassFile> findInJar(String jarName, Pattern classPattern) throws IOException {
		List<ClassFile> jars = new ArrayList<ClassFile>();
		
		JarFile jar = new JarFile(jarName);
		for (Enumeration<JarEntry> entries = jar.entries(); entries.hasMoreElements();) {
			JarEntry entry = entries.nextElement();
			String entryName = entry.getName();
			if (entryName.endsWith(CLASS_EXT)) {
				entryName = entryName.replace(FILE_SEP, PACKAGE_SEP);
				entryName = entryName.substring(0, entryName.lastIndexOf(CLASS_EXT));
				if (classPattern.matcher(entryName).matches()) {
					jars.add(new ClassFile(jarName, entryName));
				}
			}
		}
		return jars;
	}
}
